home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
11587
/
11587.xpi
/
chrome
/
aviary.jar
/
content
/
pearlutil-grab.js
< prev
next >
Wrap
Text File
|
2009-08-11
|
32KB
|
937 lines
/* Copyright (c) 2006-2009 Pearl Crescent, LLC. All Rights Reserved. */
/* vim: set sw=2 sts=2 ts=8 et syntax=javascript: */
/*
* This file is part of the Pearl Crescent Utility Functions Library.
*/
if (!com) var com = {};
if (!com.aviary) com.aviary = {};
if (!com.aviary.talon) com.aviary.talon = {};
if (!com.aviary.talon.grab) com.aviary.talon.grab =
{
kSelectionPopupElemID: "AviarySelectionPopup",
kPortionCanvasID: "AviaryPortionCanvas", // Gray w/crosshairs.
kPortionWinCanvasID: "AviaryWindowCanvas", // Window image.
kPortionBoxID: "AviaryPortionBox",
kPortionInfoID: "AviaryPortionInfoBox",
kPortionDimensionBoxID: "AviaryPortionDimensionBox", // in info box
kPortionBtnBoxID: "AviaryPortionBtnBox", // in info box
kDefaultSelectionFillStyle: "rgba(128,128,128,0.5)",
kMinWidth: 6, // When adjusting, box will be 6x6 or larger.
kLeftAlignInfoBox: true, // Change as desired.
mUtilObj: null,
mWindow: null,
mCanvasRect: {},
mSelectionFillStyle: null,
mMaxCanvasDimension: 0,
mAllowAdjustment: false,
mCaptureFunc: null,
mCaptureArg: null,
mBrowserElem: null,
mIsDrawing: false,
mIsAdjusting: false, // Initial rect has been drawn and may be adjusted.
mIsMovingBox: false,
mIsResizingBox: false,
mDidCapture: false,
mPopupScreenX: 0, // mPopupScreenX, mPopupScreenY are popup's top, left.
mPopupScreenY: 0,
mStartX: 0,
mStartY: 0,
mSelectionWidth: 0, // Only valid when mIsAdjusting is true.
mSelectionHeight: 0, // Only valid when mIsAdjusting is true.
mAdjustOffsetX: 0, // Offset within the box where mousedown occurred.
mAdjustOffsetY: 0,
mAdjustHorz: 0,
mAdjustVert: 0,
mPopupElem: null, // Popup (the container for everything).
mCanvasElem: null, // Gray w/crosshairs.
mWinCanvasElem: null, // Image of window contents.
mPortionBoxElem: null, // Surrounded by dashed lines; shown during adjustment.
mInfoBoxElem: null, // Container for dimension labels and buttons.
mButtonBoxElem: null, // Container for buttons (within info box).
mDimensionBoxLabelElem1: null, // label element with pearl-template="PROP"
mDimensionBoxLabelElem2: null, // label element with pearl-template="PROP"
mDimensionBoxLabelTemplate1: null, // e.g., "%S w" or "%1$S x %2$S pixels"
mDimensionBoxLabelTemplate2: null, // e.g., "%S h" or null
mFFZoomLevel: 1,
// aCaptureFunc is called like:
// aCaptureFunc(browserWin, portionRect, captureArg);
// where portionRect includes: startX, startY, pageW, pageH properties.
// If the user cancelled the grab, aCaptureFunc() will be called with a
// null portionRect.
init: function(aBrowserWin, aBrowserWinVisRect, aSelectionFillStyle,
aMaxCanvasDimension, aAllowAdjustment, aCaptureFunc,
aCaptureArg)
{
this.mUtilObj = com.aviary.talon.pearlutil;
this.mWindow = aBrowserWin;
this.mCanvasRect = aBrowserWinVisRect;
this.mSelectionFillStyle = (aSelectionFillStyle)
? aSelectionFillStyle
: this.kDefaultSelectionFillStyle;
if (aMaxCanvasDimension && aMaxCanvasDimension > 0)
this.mMaxCanvasDimension = aMaxCanvasDimension;
else
{
var ua = navigator.userAgent;
var isWinOrMac = (ua.indexOf("Macintosh") >= 0
|| ua.indexOf("Windows") >= 0);
this.mMaxCanvasDimension = isWinOrMac ? 32767 : 32766;
}
this.mAllowAdjustment = aAllowAdjustment;
this.mCaptureFunc = aCaptureFunc;
this.mCaptureArg = aCaptureArg;
this.mBrowserElem = top.getBrowser().selectedBrowser;
this.mIsDrawing = false;
this.mIsAdjusting = false;
this.mIsMovingBox = false;
this.mIsResizingBox = false;
this.mDidCapture = false;
this.mPopupScreenX = 0;
this.mPopupScreenY = 0;
this.mStartX = 0;
this.mStartY = 0;
this.mSelectionWidth = 0;
this.mSelectionHeight = 0;
this.mAdjustOffsetX = 0;
this.mAdjustOffsetY = 0;
this.mAdjustHorz = 0;
this.mAdjustVert = 0;
this.mPortionBoxElem = null;
this.mInfoBoxElem = null;
this.mButtonBoxElem = null;
this.mDimensionBoxLabelElem1 = null;
this.mDimensionBoxLabelElem2 = null;
this.mDimensionBoxLabelTemplate1 = null;
this.mDimensionBoxLabelTemplate2 = null;
this.mFFZoomLevel = 1;
this.mWinCanvasElem = document.getElementById(this.kPortionWinCanvasID);
this.mPopupElem = document.getElementById(this.kSelectionPopupElemID);
if (this.mPopupElem)
{
document.popupNode = this.mBrowserElem;
this.mPortionBoxElem = document.getElementById(this.kPortionBoxID);
if (this.mPortionBoxElem)
this.mPortionBoxElem.setAttribute("hidden", "true");
var dimBoxElem = document.getElementById(this.kPortionDimensionBoxID);
if (dimBoxElem && this.mUtilObj)
{
var dimElems = this.mUtilObj.GetElementsByAttr(dimBoxElem,
"pearl-template", null);
if (dimElems)
{
this.mDimensionBoxLabelElem1 = dimElems[0];
this.mDimensionBoxLabelTemplate1 =
dimElems[0].getAttribute("pearl-template");
if (dimElems.length > 1)
{
this.mDimensionBoxLabelElem2 = dimElems[1];
this.mDimensionBoxLabelTemplate2 =
dimElems[1].getAttribute("pearl-template");
}
}
}
this.mButtonBoxElem = document.getElementById(this.kPortionBtnBoxID);
this.mInfoBoxElem = document.getElementById(this.kPortionInfoID);
if (this.mInfoBoxElem)
{
// Set top and left so size is available, and hide info box for now.
this.mInfoBoxElem.style.top = "0px";
this.mInfoBoxElem.style.left = "0px";
}
this.showElement(this.mInfoBoxElem, false);
this.showElement(this.mButtonBoxElem, false);
this.mFFZoomLevel = (this.mBrowserElem.boxObject.width
/ this.mBrowserElem.contentWindow.innerWidth);
var r = { startX: 0, startY: 0, pageW: 0, pageH: 0 };
this.getContentWindowSize(r);
this.capPortionRect(r);
this.mCanvasElem = document.getElementById(this.kPortionCanvasID);
this.setCanvasSize(this.mCanvasElem, r.pageW, r.pageH);
var self = this;
window.setTimeout(function() { self.delayedInit(); }, 0);
}
},
// delayedInit() is needed so popups such as menus have a chance to close.
delayedInit: function()
{
if (this.mPopupElem)
{
// Remove old max width and height so as not to interfere with natural
// width and height (which are used in initCanvasInPopup() to set
// max width and max height).
this.mPopupElem.style.removeProperty("max-width");
this.mPopupElem.style.removeProperty("max-height");
this.mPopupElem.showPopup(this.mBrowserElem, -1, -1, "popup", "topleft",
"overlap");
this.mPopupElem.addEventListener("mousedown", this, true);
this.mPopupElem.addEventListener("mousemove", this, true);
}
},
// Called via "onpopupshown"
initCanvasInPopup: function()
{
this.mDidCapture = false;
if (this.mPopupElem)
{
this.mPopupScreenX = this.mPopupElem.boxObject.screenX;
this.mPopupScreenY = this.mPopupElem.boxObject.screenY;
}
try
{
// Convert from zoomed units to XUL pixel units.
this.mCanvasRect.pageW =
Math.round(this.mCanvasRect.pageW * this.mFFZoomLevel);
this.mCanvasRect.pageH =
Math.round(this.mCanvasRect.pageH * this.mFFZoomLevel);
this.capPortionRect(this.mCanvasRect);
var canvascontext = this.mCanvasElem.getContext("2d");
canvascontext.fillStyle = this.mSelectionFillStyle;
canvascontext.fillRect(0, 0,
this.mCanvasRect.pageW, this.mCanvasRect.pageH);
this.drawWindowInCanvas();
}
catch (e) {}
if (this.mPopupElem)
{
// Ensure that popup will not grow larger than window content size.
this.mPopupElem.style.maxWidth = this.mPopupElem.boxObject.width + "px";
this.mPopupElem.style.maxHeight = this.mPopupElem.boxObject.height + "px";
}
},
capPortionRect: function(aRect)
{
if (aRect)
{
if (aRect.pageW > this.mMaxCanvasDimension)
aRect.pageW = this.mMaxCanvasDimension;
if (aRect.pageH > this.mMaxCanvasDimension)
aRect.pageH = this.mMaxCanvasDimension;
}
},
// Sets pageW and pageH properties inside aSizeObj (units are XUL pixels).
getContentWindowSize: function(aSizeObj)
{
aSizeObj.pageW = 0;
aSizeObj.pageH = 0;
if (this.mBrowserElem)
{
var theWin = this.mBrowserElem.contentWindow;
aSizeObj.pageW = this.mBrowserElem.boxObject.width;
aSizeObj.pageH = this.mBrowserElem.boxObject.height;
var hasHorzSB = (theWin.scrollMaxX > 0);
var hasVertSB = (theWin.scrollMaxY > 0);
if (!hasHorzSB && !hasVertSB)
return; // No scrollbars so no further adjustments needed.
try
{
// Add hidden element with height=100% and use to account for SB height.
var tmpElem = theWin.document.createElement("div");
tmpElem.setAttribute("style", "visibility: hidden; z-index: -1;"
+ " position: fixed; top: 0px; left: 0px;"
+ " margin: 0px; padding: 0px; border: none;"
+ " width: 100%; height: 100%");
theWin.document.body.appendChild(tmpElem);
if (hasVertSB)
aSizeObj.pageW = Math.round(tmpElem.offsetWidth * this.mFFZoomLevel);
if (hasHorzSB)
aSizeObj.pageH = Math.round(tmpElem.offsetHeight * this.mFFZoomLevel);
theWin.document.body.removeChild(tmpElem);
} catch (e) {}
}
},
drawWindowInCanvas: function()
{
if (!this.mWinCanvasElem)
return;
var bgColor = "rgb(255,255,255)";
if (this.mUtilObj)
{
if (!this.mUtilObj.GetBoolPref("browser.display.use_system_colors",
false))
{
bgColor = this.mUtilObj.GetLocalizedStrPref(
"browser.display.background_color", bgColor);
}
}
// else get system background color... but there is no JS API.
this.setCanvasSize(this.mWinCanvasElem,
this.mCanvasRect.pageW, this.mCanvasRect.pageH);
var context = this.mWinCanvasElem.getContext("2d");
// Draw the page image.
context.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
context.save();
context.scale(this.mFFZoomLevel, this.mFFZoomLevel);
var right = Math.round(this.mCanvasRect.pageW / this.mFFZoomLevel);
var bottom = Math.round(this.mCanvasRect.pageH / this.mFFZoomLevel);
context.drawWindow(this.mWindow, this.mCanvasRect.startX,
this.mCanvasRect.startY, right, bottom, bgColor);
context.restore();
},
setCanvasSize: function(aCanvas, aWidth, aHeight)
{
aCanvas.style.width = aWidth + "px";
aCanvas.style.height = aHeight + "px";
aCanvas.style.maxWidth = aWidth + "px";
aCanvas.style.maxHeight = aHeight + "px";
aCanvas.width = aWidth;
aCanvas.height = aHeight;
},
handleEvent: function(aEvent)
{
if (aEvent.type == "keypress")
{
aEvent.preventDefault();
aEvent.stopPropagation();
this.cleanUp(); // Cancelled.
return true;
}
// The remaining events are mouse events.
var clientX = aEvent.screenX - this.mPopupScreenX;
var clientY = aEvent.screenY - this.mPopupScreenY;
if (aEvent.type == "mousemove")
{
var canvascontext = this.mCanvasElem.getContext("2d");
if (!canvascontext) return false;
if (!this.mIsDrawing)
return this.drawCrossHairs(canvascontext, clientX, clientY);
if (aEvent.ctrlKey || aEvent.shiftKey || aEvent.altKey || aEvent.metaKey)
return false;
var doUpdateCaptureRegion = false;
var captureRect = null; // Only used in !this.mIsAdjusting case.
var right = 0;
var bottom = 0;
if (!this.mIsAdjusting)
{
right = clientX;
bottom = clientY;
captureRect = this.getCaptureRect(clientX, clientY);
doUpdateCaptureRegion = true;
}
else if (this.mIsMovingBox)
{
// Move the box, ensuring all sides stay within the canvas.
this.mStartX = (clientX - this.mAdjustOffsetX);
if (this.mStartX < 0)
this.mStartX = 0;
else if (this.mStartX + this.mSelectionWidth > this.mCanvasRect.pageW)
this.mStartX = (this.mCanvasRect.pageW - this.mSelectionWidth);
this.mStartY = (clientY - this.mAdjustOffsetY);
if (this.mStartY < 0)
this.mStartY = 0;
else if (this.mStartY + this.mSelectionHeight > this.mCanvasRect.pageH)
this.mStartY = (this.mCanvasRect.pageH - this.mSelectionHeight);
this.positionBox(this.mStartX, this.mStartY, null, null);
right = this.mStartX + this.mSelectionWidth;
bottom = this.mStartY + this.mSelectionHeight;
doUpdateCaptureRegion = true;
}
else if (this.mIsResizingBox)
{
// Adjust mouse coords to account for orig. click position in grabber.
clientX += this.mAdjustOffsetX;
clientY += this.mAdjustOffsetY;
right = this.mStartX + this.mSelectionWidth;
bottom = this.mStartY + this.mSelectionHeight;
if (1 == this.mAdjustHorz)
{
this.mStartX = clientX;
if (this.mStartX < 0)
this.mStartX = 0;
if (this.mStartX > (right - this.kMinWidth))
this.mStartX = right - this.kMinWidth;
}
else if (-1 == this.mAdjustHorz)
{
right = clientX;
if (right < (this.mStartX + this.kMinWidth))
right = this.mStartX + this.kMinWidth;
else if (right > this.mCanvasRect.pageW)
right = this.mCanvasRect.pageW;
}
if (1 == this.mAdjustVert)
{
this.mStartY = clientY;
if (this.mStartY < 0)
this.mStartY = 0;
if (this.mStartY > (bottom - this.kMinWidth))
this.mStartY = bottom - this.kMinWidth;
}
else if (-1 == this.mAdjustVert)
{
bottom = clientY;
if (bottom < (this.mStartY + this.kMinWidth))
bottom = this.mStartY + this.kMinWidth;
else if (bottom > this.mCanvasRect.pageH)
bottom = this.mCanvasRect.pageH;
}
this.mSelectionWidth = right - this.mStartX;
this.mSelectionHeight = bottom - this.mStartY;
this.positionBox(this.mStartX, this.mStartY,
this.mSelectionWidth, this.mSelectionHeight);
doUpdateCaptureRegion = true;
}
if (doUpdateCaptureRegion)
{
this.drawGrayRects(canvascontext, captureRect, right, bottom);
this.updateInfoBox(captureRect); // Also shows box if hidden.
}
aEvent.preventDefault();
aEvent.stopPropagation();
return true;
}
else if (aEvent.type == "mousedown")
{
if (aEvent.ctrlKey || aEvent.shiftKey || aEvent.altKey || aEvent.metaKey)
return false;
if (aEvent.button != 0)
return false;
if (this.mIsAdjusting)
{
if (aEvent.target.id == this.kPortionBoxID) // In the box?
{
this.mAdjustOffsetX = clientX - this.mStartX;
this.mAdjustOffsetY = clientY - this.mStartY;
this.mIsMovingBox = true;
this.showElement(this.mButtonBoxElem, false);
this.updateInfoBox(null);
}
else // In a grabber.
{
var e = aEvent.target;
this.mAdjustHorz = this.getIntAttribute(e, "adjustHorz");
this.mAdjustVert = this.getIntAttribute(e, "adjustVert");
if (1 == this.mAdjustHorz)
this.mAdjustOffsetX = (this.mStartX - clientX);
else
{
var right = this.mStartX + this.mSelectionWidth;
this.mAdjustOffsetX = this.mAdjustHorz * (clientX - right);
}
if (1 == this.mAdjustVert)
this.mAdjustOffsetY = (this.mStartY - clientY);
else
{
var bottom = this.mStartY + this.mSelectionHeight;
this.mAdjustOffsetY = this.mAdjustVert * (clientY - bottom);
}
// To avoid mouse cursor "blink", temporarily set the cursor on
// the box and canvas background to match this grabber's cursor.
var cursor = e.style.cursor;
this.setElementCursor(this.mPopupElem, cursor);
this.setElementCursor(this.mPortionBoxElem, cursor);
this.mIsResizingBox = true;
this.showElement(this.mButtonBoxElem, false);
this.updateInfoBox(null);
}
return true;
}
else if (this.mIsDrawing) // workaround for lost mouseup event
return true;
// First mousedown.
this.mIsDrawing = true;
this.mStartX = clientX;
this.mStartY = clientY;
if (this.mPopupElem)
{
this.mPopupElem.addEventListener("mouseup", this, true);
this.mPopupElem.addEventListener("keypress", this, true);
}
aEvent.preventDefault();
aEvent.stopPropagation();
return true;
}
else if (aEvent.type == "mouseup")
{
aEvent.preventDefault();
aEvent.stopPropagation();
if (this.mIsAdjusting)
{
if (this.mIsMovingBox)
{
this.mIsMovingBox = false;
this.showElement(this.mButtonBoxElem, true);
}
else if (this.mIsResizingBox)
{
this.setElementCursor(this.mPopupElem, "default");
this.setElementCursor(this.mPortionBoxElem, "move");
this.mIsResizingBox = false;
this.showElement(this.mButtonBoxElem, true);
}
this.updateInfoBox(null);
}
else if (this.mIsDrawing)
{
var isValidRect = (this.mStartX != clientX && this.mStartY != clientY);
if (isValidRect)
{
var r = this.getCaptureRect(clientX, clientY);
// Ensure that rect coords are in top-bottom and left-right order.
this.mStartX = r.startX;
this.mStartY = r.startY;
this.mSelectionWidth = r.pageW;
this.mSelectionHeight = r.pageH;
if (!this.mAllowAdjustment)
this.completeGrab(); // Do not use aEvent after this point.
else
this.enterAdjustmentPhase();
}
}
return true;
}
else if (aEvent.type == "click")
{
if (this.mIsAdjusting && 2 == aEvent.detail)
this.completeGrab(); // Do not use aEvent after this point.
return true;
}
},
// Returns true if crosshairs are drawn.
drawCrossHairs: function(aCanvasCtxt, aClientX, aClientY)
{
// Provide initial crosshairs feedback before mouse is pressed.
aCanvasCtxt.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
aCanvasCtxt.fillStyle = this.mSelectionFillStyle;
aCanvasCtxt.fillRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
if (aClientX < 0 || aClientX > this.mCanvasRect.pageW ||
aClientY < 0 || aClientY > this.mCanvasRect.pageH)
{
return false;
}
aCanvasCtxt.fillStyle = "rgba(255,255,255,0.5)";
aCanvasCtxt.fillRect(aClientX, 0, 1, this.mCanvasRect.pageH);
aCanvasCtxt.fillRect(0, aClientY, this.mCanvasRect.pageW, 1);
return true;
},
// One corner of the area that is not drawn gray is (aClientX, aClientY).
// The diagonally opposite corner is (this.mStartX, this.mStartY).
// It is OK to pass null for aCaptureRect.
drawGrayRects: function(aCanvasCtxt, aCaptureRect, aClientX, aClientY)
{
// Highlight current selection rectangle by clearing entire layer and
// then redrawing 4 gray rects on sides.
aCanvasCtxt.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
aCanvasCtxt.fillStyle = this.mSelectionFillStyle;
var r = aCaptureRect ? aCaptureRect
: this.getCaptureRect(aClientX, aClientY);
if (0 != r.startX)
aCanvasCtxt.fillRect(0, 0, r.startX, this.mCanvasRect.pageH);
var w = this.mCanvasRect.pageW - r.startX;
if (0 != r.startY && 0 != w)
aCanvasCtxt.fillRect(r.startX, 0, w, r.startY);
w -= r.pageW;
var h = this.mCanvasRect.pageH - r.startY;
if (0 != w && 0 != h)
aCanvasCtxt.fillRect(r.startX + r.pageW, r.startY, w, h);
h -= r.pageH;
if (0 != r.pageW && 0 != h)
aCanvasCtxt.fillRect(r.startX, r.startY + r.pageH, r.pageW, h);
},
enterAdjustmentPhase: function()
{
// Put up grab handles and "save" button (and dbl-click handler).
this.mIsAdjusting = true;
if (this.mPortionBoxElem)
{
var box = this.mPortionBoxElem;
box.style.position = "absolute";
box.style.overflow = "hidden";
this.positionBox(this.mStartX, this.mStartY,
this.mSelectionWidth, this.mSelectionHeight);
box.style.MozOutlineWidth = "1px";
box.style.MozOutlineStyle = "dashed";
box.style.MozOutlineColor = "black";
this.setElementCursor(box, "move");
if (this.mUtilObj)
{
const kStrName = "REGION_CAPTURE_TOOLTIP";
var tt = this.mUtilObj.GetLocalizedString(kStrName);
if (tt && tt != kStrName)
box.setAttribute("tooltiptext", tt);
}
box.addEventListener("click", this, true);
box.addEventListener("mousedown", this, true);
box.removeAttribute("hidden");
this.showElement(this.mButtonBoxElem, true);
this.updateInfoBox(null);
}
if (this.mPopupElem)
{
// Remove mousedown handler and crosshairs cursor from background.
this.mPopupElem.removeEventListener("mousedown", this, true);
this.setElementCursor(this.mPopupElem, "default");
}
},
getIntAttribute: function(aElem, aAttr)
{
if (!aElem || !aAttr)
return 0;
return parseInt(aElem.getAttribute(aAttr), 10);
},
setElementCursor: function(aElem, aCursorName)
{
if (aElem && aCursorName)
aElem.style.setProperty("cursor", aCursorName, "important");
},
positionBox: function(aLeft, aTop, aWidth, aHeight)
{
if (this.mPortionBoxElem)
{
const kBorderSize = 1; // Must match box.style.MozOutlineWidth set above.
aLeft += kBorderSize;
aTop += kBorderSize;
this.mPortionBoxElem.style.left = "" + aLeft + "px";
this.mPortionBoxElem.style.top = "" + aTop + "px";
if (aWidth)
{
var innerW = aWidth - (3 * kBorderSize); // Why 3 * and not 2 *???
this.mPortionBoxElem.style.width = "" + innerW + "px";
}
if (aHeight)
{
var innerH = aHeight - (2 * kBorderSize);
this.mPortionBoxElem.style.height = "" + innerH + "px";
}
}
},
// Reposition, update width and height labels, and show info box.
// If aCaptureRect is null, coordinates are taken from member variables.
updateInfoBox: function(aCaptureRect)
{
if (!this.mInfoBoxElem)
return;
var left;
var top;
var width;
var height;
if (aCaptureRect)
{
left = aCaptureRect.startX;
top = aCaptureRect.startY;
width = aCaptureRect.pageW;
height = aCaptureRect.pageH;
}
else
{
left = this.mStartX;
top = this.mStartY;
width = this.mSelectionWidth;
height = this.mSelectionHeight;
}
// Update dimensions text (one or two labels).
if (this.mDimensionBoxLabelElem1 && this.mUtilObj)
{
if (this.mDimensionBoxLabelElem2)
{
this.mDimensionBoxLabelElem1.value = this.mUtilObj
.GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate1,
[width], 1);
this.mDimensionBoxLabelElem2.value = this.mUtilObj
.GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate2,
[height], 1);
}
else
{
this.mDimensionBoxLabelElem1.value = this.mUtilObj
.GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate1,
[width, height], 2);
}
}
// Set width of info box to match width of region. The box may become
// wider (as needed to accommodate its contents).
this.mInfoBoxElem.style.width = "" + width + "px";
if (0 == this.mInfoBoxElem.boxObject.width)
{
// Need to show it to obtain valid width.
this.showElement(this.mInfoBoxElem, true);
}
var infoWidth = this.mInfoBoxElem.boxObject.width;
var infoHeight = this.mInfoBoxElem.boxObject.height;
// To avoid jumpiness, hide info box while we adjust it.
this.showElement(this.mInfoBoxElem, false);
var keepHidden = false;
// Keep the info elements on the popup (don't let popup stretch).
// Place info below the box, aligned on the right edge if it will fit.
// If not, try above or inside box (moving it to the right if necessary).
var newTop = top + height;
if (infoHeight + newTop >= this.mCanvasRect.pageH)
{
// Not enough space below the box.
if (top > infoHeight) // Place it above the box.
newTop = top - infoHeight;
else if (infoHeight < height) // Place it inside.
newTop = top + height - infoHeight - 10;
else
keepHidden = true; // No room for info box.
}
var newLeft;
if (this.kLeftAlignInfoBox)
{
newLeft = left;
if (newLeft + infoWidth > this.mCanvasRect.pageW)
newLeft = this.mCanvasRect.pageW - infoWidth;
}
else
newLeft = left + width - infoWidth;
if (newLeft < 0)
newLeft = 0;
if (infoWidth > this.mCanvasRect.pageW)
keepHidden = true; // No room for info box.
this.mInfoBoxElem.style.top = "" + newTop + "px";
this.mInfoBoxElem.style.left = "" + newLeft + "px";
if (!keepHidden)
keepHidden = (0 == width || 0 == height); // Hide if nothing to capture.
if (!keepHidden)
this.showElement(this.mInfoBoxElem, true);
},
showElement: function(aElem, aDoShow)
{
if (aElem)
{
if (aDoShow)
aElem.removeAttribute("hidden");
else
aElem.setAttribute("hidden", "true");
}
},
getCaptureRect: function(aEventClientX, aEventClientY)
{
var l, t, r, b;
if (this.mStartX < aEventClientX)
{
l = this.mStartX;
r = aEventClientX;
}
else
{
l = aEventClientX;
r = this.mStartX;
}
if (l < 0) l = 0;
if (r > this.mCanvasRect.pageW) r = this.mCanvasRect.pageW;
if (this.mStartY < aEventClientY)
{
t = this.mStartY;
b = aEventClientY;
}
else
{
t = aEventClientY;
b = this.mStartY;
}
if (t < 0) t = 0;
if (b > this.mCanvasRect.pageH) b = this.mCanvasRect.pageH;
return { startX: l, startY: t, pageW: r - l, pageH: b - t };
},
completeGrab: function(aGrabParam)
{
this.mDidCapture = true;
this.cleanUp();
if (this.mCaptureFunc)
{
// TODO: sometimes the captured image has a horizontal or vertical
// black line in it.
var r = { startX: this.mStartX, startY: this.mStartY,
pageW: this.mSelectionWidth, pageH: this.mSelectionHeight };
r.startX = Math.round(r.startX / this.mFFZoomLevel)
+ this.mWindow.pageXOffset;
r.startY = Math.round(r.startY / this.mFFZoomLevel)
+ this.mWindow.pageYOffset;
r.pageW = Math.round(r.pageW / this.mFFZoomLevel);
r.pageH = Math.round(r.pageH / this.mFFZoomLevel);
this.mCaptureFunc(this.mWindow, r, this.mCaptureArg, aGrabParam);
}
},
deinitCanvasInPopup: function()
{
if (this.mPopupElem)
{
this.mPopupElem.removeEventListener("mousedown", this, true);
this.mPopupElem.removeEventListener("mousemove", this, true);
this.mPopupElem.removeEventListener("mouseup", this, true);
this.mPopupElem.removeEventListener("keypress", this, true);
}
if (this.mPortionBoxElem)
{
this.mPortionBoxElem.removeEventListener("click", this, true);
this.mPortionBoxElem.removeEventListener("mousedown", this, true);
}
if (this.mCanvasElem)
{
var canvascontext = this.mCanvasElem.getContext("2d");
if (canvascontext)
{
canvascontext.clearRect(0, 0,
this.mCanvasRect.pageW, this.mCanvasRect.pageH);
}
}
if (this.mWinCanvasElem)
{
var canvascontext = this.mWinCanvasElem.getContext("2d");
if (canvascontext)
{
canvascontext.clearRect(0, 0,
this.mCanvasRect.pageW, this.mCanvasRect.pageH);
}
}
// If no capture was done, notify caller after canvas popup is done.
if (!this.mDidCapture && this.mCaptureFunc)
{
var self = this;
setTimeout(function() { self.mCaptureFunc(self.mWindow, null,
self.mCaptureArg) }, 0);
}
},
cleanUp: function()
{
if (this.mPopupElem)
this.mPopupElem.hidePopup();
this.mIsDrawing = false;
this.mDidCapture = false;
},
/*
pearlDumpObj: function(aLabel, aObj)
{
if (aObj)
{
if (aLabel)
dump(aLabel + ":\n");
for (var p in aObj)
dump(" " + p + ": " + aObj[p] + "\n");
}
},
*/
/*
dumpBoxes: function(aElem, aIndent)
{
if (!aIndent)
aIndent = "";
if (aElem) try
{
var node = aElem.QueryInterface(Components.interfaces.nsIDOMNode);
var w;
var h;
var b = "unknown";
if (node.boxObject)
{
w = node.boxObject.width;
h = node.boxObject.height;
b = h + (node.boxObject.y - node.parentNode.boxObject.y);
}
else
{
w = aElem.clientWidth;
h = aElem.clientHeight;
}
var name = node.nodeName;
var id = node.id ? node.id : "-none-";
var childCount = node.childNodes.length;
dump(aIndent + name + " (" + id + ") - w: " + w + ", h: " + h
+ ", b: " + b + " (" + childCount + " children)\n");
for (var child = node.firstChild; child != null; child = child.nextSibling)
this.dumpBoxes(child, " " + aIndent);
} catch (e) { dump(e + "\n"); }
},
*/
endOfObject: true
}